#include "LogReg.h"

std::string Generate()
{
    srand(time(nullptr));
    std::string s;
    s.resize(16); // 16个字节的盐
    for (int i = 0; i < 16; i++)
    {
        // 字符区间：33~126（可见字符 - ' '）
        s[i] = rand() % 94 + 33;
    }
    return s; // 盐值
}

// 哈希加盐
std::pair<std::string, std::string> HashWithSalt(const std::string &passwd)
{
    auto salt = Generate();
    auto TruePasswd = passwd + salt;
    unsigned char hash[SHA256_DIGEST_LENGTH] = {0};
    SHA256((const unsigned char *)TruePasswd.c_str(), TruePasswd.size(), hash);

    std::string s;
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++)
    {
        char temp[3] = {0}; // 两个位置放十六进制，一个放\0
        snprintf(temp, sizeof(temp), "%02x", hash[i]);
        s += temp;
    }
    return {s, salt};
}

// 判断密码是否相等
bool IsPasswdSame(const std::string &passwd, const std::string &salt, const std::string &Hash)
{
    auto TruePasswd = passwd + salt;
    unsigned char hash[SHA256_DIGEST_LENGTH] = {0};
    SHA256((const unsigned char *)TruePasswd.c_str(), TruePasswd.size(), hash);

    std::string s;
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++)
    {
        char temp[3] = {0}; // 两个位置放十六进制，一个放\0
        snprintf(temp, sizeof(temp), "%02x", hash[i]);
        s += temp;
    }

    return s == Hash;
}

// 登录
void Login()
{
    while (1)
    {
        // 获取登陆界面返回的数据
        auto [name, passwd] = CreateLoginInterface();
        // 从存储用户账号文件夹里读出数据
        auto TxtVec = FileTools::ReadLine("./user.txt");
        for (auto &Line : TxtVec)
        {
            StdMyString s(Line.c_str());
            MyStringList l = s.split(" ");
            auto Account = l[0];
            auto Passwd = l[1];
            auto Salt = l[2];
            if(Account == name.c_str() && IsPasswdSame(passwd, Salt.c_str(), Passwd.c_str()))
            {
                std::cout << "登陆成功！\n";
                sleep(1);

                // 游戏界面
                Player p(name);
                Scene s(WIDTH, HEIGHT, p);
                Scene2 s2(WIDTH, HEIGHT, p);
                Scene3 s3(WIDTH, HEIGHT, p);

                // 读档
                std::string fileName = CreateReadFileInterface();
                s.ReadPlayer(fileName);
                s.ReadMonster(fileName);
                s.ReadBox(fileName);
                s.ReadBag(fileName);
                
                if (p.GetFloor() == 1)
                {
                    while(1)
                    {
                        system("clear"); // 清空屏幕
                        s.show();
                        p.show();
                        s.Save(fileName);
                        s.BuyInShop();

                        Monster *m = s.IsMonsInSamePlace();
                        if(m)
                        {
                            Battle(p, *m);
                        }

                        Box *b = s.IsBoxInSamePlace();
                        if(b)
                        {
                            b->OpenBox(p);
                        }

                        Ladder *l = s.IsLadderInSamePlace();
                        if(l)
                        {
                            Scene2 s2(WIDTH, HEIGHT, p);
                            while(1)
                            {
                                system("clear"); // 清空屏幕
                                s2.show2();
                                p.show();
                                s2.Save(fileName); 
                                s2.BuyInShop();

                                Monster *m = s2.IsMonsInSamePlace();
                                if(m)
                                {
                                    Battle(p, *m);
                                }

                                Box *b = s2.IsBoxInSamePlace();
                                if(b)
                                {
                                    b->OpenBox(p);
                                }

                                Ladder *l2 = s2.IsLadderInSamePlace();
                                if(l2)
                                {
                                    Scene3 s3(WIDTH, HEIGHT, p);
                                    while(1)
                                    {
                                        system("clear"); // 清空屏幕
                                        s3.show3();
                                        p.show();
                                        s3.Save(fileName);
                                        s3.BuyInShop();

                                        Monster *m = s3.IsMonsInSamePlace();
                                        if(m)
                                        {
                                            Battle(p, *m);
                                        }

                                        Box *b = s3.IsBoxInSamePlace();
                                        if(b)
                                        {
                                            b->OpenBox(p);
                                        }

                                        s3.IsLadderInSamePlace();
                                    }
                                }
                            }
                        }
                    }
                }

                if (p.GetFloor() == 2)
                {
                    // 读档
                    s2.ReadPlayer(fileName);
                    s2.ReadMonster(fileName);
                    s2.ReadBox(fileName);
                    s2.ReadBag(fileName);

                    while(1)
                    {
                        system("clear"); // 清空屏幕
                        s2.show2();
                        p.show();
                        s2.Save(fileName); 
                        s2.BuyInShop();

                        Monster *m = s2.IsMonsInSamePlace();
                        if(m)
                        {
                            Battle(p, *m);
                        }

                        Box *b = s2.IsBoxInSamePlace();
                        if(b)
                        {
                            b->OpenBox(p);
                        }

                        Ladder *l2 = s2.IsLadderInSamePlace();
                        if(l2)
                        {
                            Scene3 s3(WIDTH, HEIGHT, p);
                            while(1)
                            {
                                system("clear"); // 清空屏幕
                                s3.show3();
                                p.show();
                                s3.Save(fileName);
                                s3.BuyInShop();

                                Monster *m = s3.IsMonsInSamePlace();
                                if(m)
                                {
                                    Battle(p, *m);
                                }

                                Box *b = s3.IsBoxInSamePlace();
                                if(b)
                                {
                                    b->OpenBox(p);
                                }

                                s3.IsLadderInSamePlace();
                            }
                        }
                    }
                }

                if (p.GetFloor() == 3)
                {
                    // 读档
                    s3.ReadPlayer(fileName);
                    s3.ReadMonster(fileName);
                    s3.ReadBox(fileName);
                    s3.ReadBag(fileName);

                    while(1)
                    {
                        system("clear"); // 清空屏幕
                        s3.show3();
                        p.show();
                        s3.Save(fileName);
                        s3.BuyInShop();

                        Monster *m = s3.IsMonsInSamePlace();
                        if(m)
                        {
                            Battle(p, *m);
                        }

                        Box *b = s3.IsBoxInSamePlace();
                        if(b)
                        {
                            b->OpenBox(p);
                        }

                        s3.IsLadderInSamePlace();
                    }
                } 
            }
        }
        std::cout << "登录失败！\n";
        sleep(1);
    }
}

// 注册
void Register()
{
    while (true)
    {
        // 获取注册界面返回的数据
        auto [name, truePasswd]  = CreateRegisterInterface();

        // 检查用户名是否已存在
        bool nameExist = false;
        auto txtVec = FileTools::ReadLine("./user.txt");
        for (const auto &Line : txtVec)
        {
            StdMyString s(Line.c_str());
            MyStringList l = s.split(" ");
            if (l[0] == name.c_str())
            {
                std::cout << "用户名已存在，请重新创建一个用户名！\n";
                nameExist = true;
                break;
            }
        }

        // 如果用户名已存在，则重新输入
        if (nameExist)
        {
            continue;
        }

        auto [passwd, salt] = HashWithSalt(truePasswd);
        std::vector<std::string> vec = {name + " " + passwd + " " + salt};

        FileTools::MakeDir("./存档/" + name);
        FileTools::MakeDir("./存档/" + name + "/存档一");
        FileTools::MakeDir("./存档/" + name + "/存档二");
        FileTools::MakeDir("./存档/" + name + "/存档三");

        FileTools::SetTxt("./存档/" + name + "/存档一/Player.txt");
        FileTools::SetTxt("./存档/" + name + "/存档二/Player.txt");
        FileTools::SetTxt("./存档/" + name + "/存档三/Player.txt");

        FileTools::SetTxt("./存档/" + name + "/存档一/Monster.txt");
        FileTools::SetTxt("./存档/" + name + "/存档二/Monster.txt");
        FileTools::SetTxt("./存档/" + name + "/存档三/Monster.txt");

        FileTools::SetTxt("./存档/" + name + "/存档一/Box.txt");
        FileTools::SetTxt("./存档/" + name + "/存档二/Box.txt");
        FileTools::SetTxt("./存档/" + name + "/存档三/Box.txt");

        FileTools::SetTxt("./存档/" + name + "/存档一/Bag.txt");
        FileTools::SetTxt("./存档/" + name + "/存档二/Bag.txt");
        FileTools::SetTxt("./存档/" + name + "/存档三/Bag.txt");

        FileTools::AppendLine("./user.txt", vec);
        break;
    }
}
